package shoot;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import shoot.FlyingObject.*;
import java.util.Arrays;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

/**
 * @author: dongshipan
 * @date: 2021/7/5 16:50
 * @description:
 */
public class World extends JPanel {

    /**
     * 开始图片
     */
    private static BufferedImage pasue;
    /**
     * 暂停图片
     */
    private static BufferedImage gameover;
    /**
     * 游戏结束图片
     */
    private static BufferedImage start;

    /**
     * 将三个图片读取到图片对象中
     */
    static {
        start = BaseFlyingObject.readImage("start.png");
        pasue = BaseFlyingObject.readImage("pause.png");
        gameover = BaseFlyingObject.readImage("gameover.png");
    }

    // 声明一个属性，表示当前窗口游戏状态
    /**
     * 程序开始时是 启动，但未开始状态
     */
    private int state = FlyConstant.START;
    /**
     * 游戏的分数
     */
    private int score;
    /**
     * 声明游戏中只有一个对象的类型
     */
    Hero hero = Hero.getHero();
    Sky sky = new Sky();
    /**
     * 声明游戏中存在的引用类型数组
     */
    BaseFlyingObject[] enemy = {};
    Bullet[] bullets = {};

    /**
     * 游戏开始方法
     */
    public void start() {
        //创建一个监听对象
        MouseAdapter ad = new MouseAdapter() {
            // 匿名内部类，监听鼠标
            @Override
            public void mouseMoved(MouseEvent e) {
                int x = e.getX(); //获得鼠标的 x 坐标
                int y = e.getY(); //获得鼠标的 y 坐标
                // 让英雄机移动到该位置
                if (state == FlyConstant.RUNNING) {
                    hero.moveTo(x, y);
                }
            }

            // 监听鼠标点击事件
            @Override
            public void mouseClicked(MouseEvent e) {
                switch (state) {
                    case FlyConstant.START:
                        // 如果是游戏开始状态时点击鼠标
                        state = FlyConstant.RUNNING;
                        //游戏进入运行状态
                        break;
                    case FlyConstant.GAME_OVER:
                        //如果时游戏结束状态
                        // 将状态改为开始
                        state = FlyConstant.START;
                        // 重置游戏窗口
                        score = 0;
                        hero = Hero.getHero();
                        sky = new Sky();
                        enemy = new BaseFlyingObject[0];
                        bullets = new Bullet[0];
                        break;
                    default:
                        break;
                }
            }

            // 监听鼠标移出事件
            @Override
            public void mouseExited(MouseEvent e) {
                //如果游戏运行时，鼠标移出
                if (state == FlyConstant.RUNNING) {
                    //进入暂停状态
                    state = FlyConstant.PAUSE;
                }
            }

            //监听鼠标移入事件
            @Override
            public void mouseEntered(MouseEvent e) {
                //如果游戏暂停状态时，鼠标移入
                if (state == FlyConstant.PAUSE) {
                    //游戏继续
                    state = FlyConstant.RUNNING;
                }
            }
        };
        // 监听器注册窗口事件
        // 鼠标移动时和滑动时
        this.addMouseListener(ad);
        this.addMouseMotionListener(ad);
        //游戏的主记时器

        Timer timer = new Timer();
        //定义机时器的时间间隔
        int interval = 5;
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                if (state == FlyConstant.RUNNING) {
                    stepAction();
                    //开始运动
                    enterAction();
                    //敌军进场
                    shootAction();
                    // 子弹进场
                    outOfBoundsAction();
                    // 移除越界内容
                    bulleHitAction();
                    // 判断子弹击中敌人
                    heroHitAction();
                    // 判断英雄机撞击敌人
                    checkGameOverAction();
                    // 检测英雄机生命 值，为 0 时游戏结束
                }
                // 重新绘制
                repaint();
            }
        };
        //     //启动计时器
        timer.schedule(task, interval, interval);
    }

    //飞行物移动
    public void stepAction() {
        //计时器会每隔一定时间运行这个方法 //天空移动
        sky.step();
        //小大蜜移动
        for (int i = 0; i < enemy.length; i++) {
            enemy[i].step();
        }
        for (int i = 0; i < bullets.length; i++) {
            bullets[i].step();
        }
    }

    //进场计数变量
    int enter = 0; //敌机进场

    public void enterAction() {
        enter++;
        //每次运行变量+1
        if (enter == 20) {
            BaseFlyingObject fly = nextEnemy();
            //生成一个敌军
            enemy = Arrays.copyOf(enemy, enemy.length + 1);
            enemy[enemy.length - 1] = fly;
            enter = 0;
        }
    }

    int shoot = 0;

    //子弹进场
    public void shootAction() {
        shoot++;
        if (shoot == 20) {
            //获得英雄机发射的子弹
            Bullet[] bs = hero.shoot();
            bullets = Arrays.copyOf(bullets, bullets.length + bs.length);
            System.arraycopy(bs, 0, bullets, bullets.length - bs.length, bs.length);
                /*
                if(bs.length==1) {
                bullets[bullets.length-1]=bs[0];
                }else if(bs.length==2){
                bullets[bullets.length-2]=bs[0];
                bullets[bullets.length-1]=bs[1];
                }*/
            shoot = 0;
        }
    }

    //删除越界内容（敌机/子弹）的方法
    public void outOfBoundsAction() {
        //计时器周期调用
        int index = 0;
        // 统计没有越界敌人的个数，和下标
        // 创建新数组，存放没有越界的敌人
        BaseFlyingObject[] lives = new BaseFlyingObject[enemy.length];
        for (int i = 0; i < enemy.length; i++) {
            if (!enemy[i].outOfBounds() && !enemy[i].isRemove()) {
                lives[index] = enemy[i];
                index++;
            }
        }
        //将没有出界的敌机数组所容
        enemy = Arrays.copyOf(lives, index);
        index = 0;
        //index 清 0，为子弹出界使用
        Bullet[] bs = new Bullet[bullets.length];
        for (int i = 0; i < bullets.length; i++) {
            if (!bullets[i].outOfBounds() && !bullets[i].isRemove()) {
                bs[index] = bullets[i];
                index++;
            }
        }
        bullets = Arrays.copyOf(bs, index);
    }

    //子弹与敌机碰撞的方法
    public void bulleHitAction() {
        //遍历所有子弹
        for (int i = 0; i < bullets.length; i++) {
            //获得当前遍历的子弹，以便后面代码使用
            Bullet b = bullets[i];
            //遍历所有敌人
            for (int j = 0; j < enemy.length; j++) {
                //获取当前遍历的敌人
                BaseFlyingObject f = enemy[j];
                //子弹活着，敌人活着，而且撞上了
                if (b.isLife() && f.isLife() && f.hit(b)) {
                    //子弹去死
                    b.goDead();
                    // 敌机去死
                    f.goDead();
                    // 判断被击中的是不是小敌机和大敌机
                    // if (f instanceof Score) {
                    //     // 如果 f 是实现了 Score 接口的对象
                    //     score += ((Score) f).getScore();
                    // }
                    // if (f instanceof Award) {
                    //     //如果 f 是实现了 Award 接口对象
                    //     Award a = (Award) f;
                    //     switch (a.getAwardType()) {
                    //         case Award.DOUBLE_FIRE: // 奖 励 火 力值
                    //             hero.addDoubleFire();
                    //             break;
                    //         case Award.LIFE: // 奖励生命值
                    //             if (hero.getLife() <= 5) hero.addLife();
                    //             else hero.addDoubleFire();
                    //             break;
                }
            }
        }

    }

    /**
     * 英雄机和敌机的碰撞检测
     */
    public void heroHitAction() {
        //遍历所有敌机
        for (BaseFlyingObject f : enemy) {
            // 取出当前遍历的敌机
            // 检查是否发生了碰撞
            if (hero.isLife() && f.isLife() && f.hit(hero)) {
                // 敌机死
                f.goDead();
                hero.subtractLife();
                // 英雄机 - 生命值
                hero.clearDoubleFire();
                // 英雄机清空火力值
            }
        }
    }

    // 检测游戏结束
    public void checkGameOverAction() {
        if (hero.getLife() <= 0) {
            state = FlyConstant.GAME_OVER;
        }
    }

    // 生成敌机的方法(小大蜜皆有可能，返回父类类型)
    public BaseFlyingObject nextEnemy() {
        BaseFlyingObject fly;
        // 先声明返回值
        Random ran = new Random();
        int num = ran.nextInt(100);
        // 生成随机数
        if (num < 40) {
            //40%几率
            fly = new AirPlane();
        } else if (num < 80) {
            // 40 - 79 40 % 几率
            fly = new BigAirPlane();
        } else {
            // 剩下 20 % 几率
            fly = new Bee();
        }
        return fly;
    }


    /**
     * 除法所有绘制内容，绘制窗口
     * 方法名不能错，这个方法将在窗口出现时，自动被调用
     *
     * @param g 画笔
     */
    @Override
    public void paint(Graphics g) {
        sky.paintObject(g);
        // 画天空
        hero.paintObject(g);
        // 画英雄机
        for (Bullet b : bullets) {
            // 画子弹
            b.paintObject(g);
        }
        for (BaseFlyingObject e : enemy) {
            e.paintObject(g);
            //画敌军
            // 画分和画命
            g.setColor(new Color(0xFF0000));
            //设置颜色(纯红)
            g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 24));
            //设置 字体样式(字体:SANS_SERIF 样式:BOLD 加粗 字号:24)
            g.drawString("SCORE:" + score, 10, 20);
            g.drawString("LIFE：" + hero.getLife(), 10, 45);
            g.drawString("DoubleFier：" + hero.getDoubleFire(), 10, 65);
            switch (state) {
                case FlyConstant.START:
                    g.drawImage(start, 0, 0, null);
                    break;
                case FlyConstant.PAUSE:
                    g.drawImage(pasue, 0, 0, null);
                    break;
                case FlyConstant.GAME_OVER:
                    g.drawImage(gameover, 0, 0, null);
                    break;
                default:
                    break;
            }
        }
    }

    public static void main(String[] args) {
        World w = new World();
        //创建一个窗口，标题为 Fly
        JFrame frame = new JFrame("Fly");
        //将 world 对象放入窗口
        frame.add(w);
        // 设置窗口的宽、高
        frame.setSize(World.WIDTH, World.HEIGHT);
        //设置窗口关闭时程序结束
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //设置窗口剧中
        frame.setLocationRelativeTo(null);
        //窗口显示
        frame.setVisible(true);
        w.start();
    }

}